import pyautogui
import tkinter
import os
import sys
import threading
import keyboard
from typing import *
from tkinter import ttk, messagebox
import time

def resource_path(relative_path):
    if getattr(sys, "frozen", False):
        base_path = sys._MEIPASS
    else:
        # base_path = os.path.abspath(".")
        base_path = os.path.dirname(os.path.abspath(__file__))
    return os.path.join(base_path, relative_path)


mainScreen = tkinter.Tk()
mainScreen.resizable(False,False)
try:
    mainScreen.iconbitmap(resource_path(os.path.join("logo.ico")))
except:
    pass
mainScreen.title("连点器控制台")
mainScreenInFocus = True


def mainScreenFocusOut(event):
    global mainScreenInFocus
    # print("out")
    mainScreenInFocus = False


def mainScreenFocusIn(event):
    global mainScreenInFocus
    # print("in")
    mainScreenInFocus = True


mainScreen.bind("<FocusOut>", mainScreenFocusOut)
mainScreen.bind("<FocusIn>", mainScreenFocusIn)


mouseTarget = {
    "left": tkinter.IntVar(),
    "double": tkinter.IntVar(),
    "middle": tkinter.IntVar(),
    "right": tkinter.IntVar(),
}

gaptime = tkinter.IntVar()
gaptime.set(200)

KeyList = Dict[str, int]

keyList: KeyList = {}
startKeyList = {29, 56, 50}
onClick = False
isNewDown = True


keyboardEventListener: List[Callable[[KeyList, Any], None]] = []


def keyLoad(event):
    global keyList
    event.name = event.name.lower()
    if event.event_type == "down" and event.name not in keyList:
        keyList[event.name] = event.scan_code
    if event.event_type == "up":
        try:
            del keyList[event.name]
        except:
            pass
    for listener in keyboardEventListener:
        listener(keyList, event)


class KeyChoiceBox(ttk.Entry):
    __keyList: KeyList
    _readonly: bool = False
    _onFocus: bool = False

    def __init__(self, *args, keyList: KeyList = {}, **kw):
        super().__init__(*args, **kw)
        self.keyList = keyList
        super().config(state="readonly")
        keyboardEventListener.append(self._keyboardCallback)
        self.bind("<FocusIn>", self._onFocusIn)
        self.bind("<FocusOut>", self._onFocusOut)

    def __del__(self):
        keyboardEventListener.remove(self._keyboardCallback)

    @property
    def keyList(self):
        return self.__keyList

    @keyList.setter
    def keyList(self, keyList: KeyList):
        if self._readonly:
            return
        self.__keyList = keyList.copy()
        super().config(state="normal")
        self.delete(0, tkinter.END)
        self.insert(0, "+".join(keyList.keys()))
        super().config(state="readonly")

    def _keyboardCallback(self, keyList: KeyList, e):
        if e.event_type == "up":
            return
        if self._onFocus:
            self.keyList = keyList
        print(keyList)

    def config(self, state: Literal["normal", "readonly", None] = None, **kw):
        if state == "readonly":
            self._readonly = True
        if state == "normal":
            self._readonly = False
        super().config(**kw)

    def _onFocusIn(self, e):
        self._onFocus = True

    def _onFocusOut(self, e):
        self._onFocus = False


buttonChoiceBox = tkinter.Frame()

tkinter.Label(buttonChoiceBox, text="按键范围", fg="blue").grid(
    row=0, column=0, columnspan=2
)
buttonChoiceBox.grid(row=0, column=0, sticky="WE")
buttonChoiceBox.grid_rowconfigure(0, weight=1)

keyboardButtonChoiceBox = tkinter.Frame(buttonChoiceBox)

keyboardButtonChoiceBox.grid(row=1, column=1)

keyboardTargetInputer = KeyChoiceBox(keyboardButtonChoiceBox, width=20)
keyboardTargetInputer.grid(row=0, column=0)

mouseButtonChoiceBox = tkinter.Frame(buttonChoiceBox)

mouseButtonChoiceBox.grid(row=1, column=0)


ttk.Checkbutton(
    mouseButtonChoiceBox, text="左键单击", variable=mouseTarget["left"]
).grid(row=0, column=0, sticky="W")
ttk.Checkbutton(
    mouseButtonChoiceBox, text="左键双击", variable=mouseTarget["double"]
).grid(row=1, column=0, sticky="W")
ttk.Checkbutton(mouseButtonChoiceBox, text="中键", variable=mouseTarget["middle"]).grid(
    row=2, column=0, sticky="W"
)
ttk.Checkbutton(mouseButtonChoiceBox, text="右键", variable=mouseTarget["right"]).grid(
    row=3, column=0, sticky="W"
)

gapSetBox = tkinter.Frame(buttonChoiceBox)
gapSetBox.grid(row=2, column=1)

gapSetEntry = ttk.Entry(
    gapSetBox,
    textvariable=gaptime,
    validate="focusout",
    validatecommand=lambda: gapSetEntry.get().isdigit(),
    invalidcommand=lambda: gaptime.set(200),
)
gapSetEntry.grid(row=0, column=1)
tkinter.Label(gapSetBox,text="间隔").grid(row=0, column=0)
tkinter.Label(gapSetBox,text="ms").grid(row=0, column=2)


keyChoiceBox = tkinter.Frame()
keyChoiceBox.grid(row=1, column=0)
tkinter.Label(keyChoiceBox, text="按键绑定", fg="blue").grid(
    row=0, column=0, sticky="W"
)


keyChoice = KeyChoiceBox(keyChoiceBox, keyList={"ctrl": 29, "alt": 56, "m": 50})

keyChoice.grid(row=0, column=1, sticky="WE")

keyType = tkinter.ttk.Combobox(
    keyChoiceBox, width=11, font=("microsoft yahei", 10, "bold")
)
keyType["value"] = ("按下", "开关")
keyType.config(state="readonly")
keyType.current(0)
keyType.grid(row=0, column=2, sticky="W")

keyboard.hook(keyLoad)

def clickControl():
    global onClick, isNewDown
    while True:
        try:
            time.sleep(gaptime.get()/1000)
        except:
            time.sleep(0.2)
        if (
            set(keyList.keys()) == set(keyChoice.keyList.keys())
            and not mainScreenInFocus
        ):
            if keyType.get() == "按下":
                onClick = True
                onClickShower.config(text="正在点击")
            else:
                if isNewDown:
                    onClick = not onClick
                    if onClick:
                        onClickShower.config(text="正在点击")
                    else:
                        onClickShower.config(text="没有点击")
                    isNewDown = False
        else:
            if keyType.get() == "按下":
                onClick = False
                onClickShower.config(text="没有点击")
            else:
                isNewDown = True
        if onClick:
            if mainScreenInFocus:
                continue
            try:
                if mouseTarget["left"].get() == 1:
                    pyautogui.click()
                if mouseTarget["double"].get() == 1:
                    pyautogui.doubleClick()
                if mouseTarget["middle"] == 1:
                    pyautogui.middleClick()
                if mouseTarget["right"].get() == 1:
                    pyautogui.rightClick()
                for i in keyboardTargetInputer.keyList.values():
                    keyboard.press_and_release(i)
            except:
                messagebox.showerror(
                    "紧急中断",
                    "点击事件触发了错误,我们紧急中断了所有事件\n程序即将关闭",
                )
                os._exit(0)


def aboutShower():
    auboutScreen = tkinter.Tk()
    try:
        auboutScreen.iconbitmap(resource_path(os.path.join("logo.ico")))
    except:
        pass
    auboutScreen.title("关于")

    messageBox = tkinter.Frame(auboutScreen)
    messageBox.grid(row=0, column=0)

    createrTitle = tkinter.Label(messageBox, text="作者:")
    createrTitle.grid(row=0, column=0, sticky="W")
    creater = tkinter.Entry(messageBox)
    creater.insert(0, "宽宽")
    creater.config(state="readonly")
    creater.grid(row=0, column=1, sticky="W")

    createrQQTitle = tkinter.Label(messageBox, text="作者QQ:")
    createrQQTitle.grid(row=1, column=0, sticky="W")
    createrQQ = tkinter.Entry(messageBox, fg="blue")
    createrQQ.insert(0, "2163826131")

    def startAddQQ(event):
        os.system(
            "start https://qm.qq.com/cgi-bin/qm/qr?k=7tPR4X-U1ZVL0nPvkrPEJDFZJK1pIF68&noverify=0"
        )

    createrQQ.bind("<Button-1>", startAddQQ)
    createrQQ.config(state="readonly")
    createrQQ.grid(row=1, column=1, sticky="W")

    createrUrlTitle = tkinter.Label(messageBox, text="作者主页:")
    createrUrlTitle.grid(row=2, column=0, sticky="W")
    createrUrl = tkinter.Entry(messageBox, fg="blue")
    createrUrl.insert(0, "宽宽2007的小天地")

    def startURL(event):
        os.system("start https://kuankuan.site/")

    createrUrl.bind("<Button-1>", startURL)
    createrUrl.config(state="readonly")
    createrUrl.grid(row=2, column=1, sticky="W")

    createrGiteeTitle = tkinter.Label(messageBox, text="作者Gitee:")
    createrGiteeTitle.grid(row=3, column=0, sticky="W")
    createrGitee = tkinter.Entry(messageBox, fg="blue")
    createrGitee.insert(0, "宽宽2007")

    def startGitee(event):
        os.system("start https://gitee.com/kuankuan2007")

    createrGitee.bind("<Button-1>", startGitee)
    createrGitee.config(state="readonly")
    createrGitee.grid(row=3, column=1, sticky="W")

    createrWeiXinPayTitle = tkinter.Label(messageBox, text="赞助作者")
    createrWeiXinPayTitle.grid(row=4, column=0, sticky="W")
    createrWeiXinPay = tkinter.Entry(messageBox, fg="blue")
    createrWeiXinPay.insert(0, "微信支付")

    def startWeiXinPayTitle(event):
        os.system("start https://kuankuan.site/WeiXinPay.png")

    createrWeiXinPay.bind("<Button-1>", startWeiXinPayTitle)
    createrWeiXinPay.config(state="readonly")
    createrWeiXinPay.grid(row=4, column=1, sticky="W")

    ttk.Label(
        auboutScreen,
        text="本产品用于日常自动化办公\n不得用于作弊、外挂\n最终解释权归作者所有",
    ).grid(row=1, column=0, sticky="W")

    auboutScreen.mainloop()


def aboutBooter():
    threading.Thread(target=aboutShower, name="about", daemon=True).start()


onClickShower = tkinter.Label(mainScreen, text="没有点击", fg="red")
onClickShower.grid(row=2, column=0, sticky="W")


buttonBox = tkinter.Frame()
buttonBox.grid(row=3, column=0, sticky="E")
ttk.Button(buttonBox, text="关于", command=aboutBooter).grid(
    row=0, column=0, sticky="E"
)
messagebox.showwarning(
    "使用提示",
    "一旦本软件出现任何问题导致点击无法停止时,请将鼠标移至\n屏幕左上角\n程序将会触发错误并强行退出",
)


clickControlT = threading.Thread(
    target=clickControl, name="clickControl", daemon=True
).start()

mainScreen.mainloop()
